package cn.vawn.base.service.impl;

import cn.vawn.base.consts.EntityConsts;
import cn.vawn.base.entity.SmsVCodeBlackWhiteRecord;
import cn.vawn.base.entity.SmsVCodeRecord;
import cn.vawn.base.mapper.SmsVCodeBlackWhiteRecordMapper;
import cn.vawn.base.mapper.SmsVCodeRecordMapper;
import cn.vawn.base.service.ISmsService;
import cn.vawn.base.util.DateUtil;
import cn.vawn.base.util.PropertyUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

@Service("smsService")
public class SmsImpl implements ISmsService {

    @Autowired
    private SmsVCodeRecordMapper smsVCodeRecordMapper;

    @Autowired
    private SmsVCodeBlackWhiteRecordMapper smsVCodeBlackWhiteRecordMapper;

    @Override
    public int getVCodeProcess(String mobile, String clientIp, Integer vCodeType) {
        int process = EntityConsts.V_CODE_PROCESS_ALLOW;
        Date currentDate = new Date();
        boolean needBlack = false;
        // 是否在黑名单中
        SmsVCodeBlackWhiteRecord smsVCodeBlackWhiteRecord = new SmsVCodeBlackWhiteRecord();
        smsVCodeBlackWhiteRecord.setMobile(mobile);
        smsVCodeBlackWhiteRecord.setIp(clientIp);
        smsVCodeBlackWhiteRecord.setVCodeType(vCodeType);
        List<SmsVCodeBlackWhiteRecord> vCodeBlackRecordList = smsVCodeBlackWhiteRecordMapper.getBlackRecordByMobileOrIp(smsVCodeBlackWhiteRecord, currentDate);
        if (vCodeBlackRecordList != null && vCodeBlackRecordList.size() > 0) {
            process = EntityConsts.V_CODE_PROCESS_BLACK;
        }
        // 有限制请求次数的验证码类型
        if (isRestrictRequest(vCodeType)) {
            // 当天请求记录
            if (process == EntityConsts.V_CODE_PROCESS_ALLOW) {
                SmsVCodeRecord smsVCodeRecordDay = new SmsVCodeRecord();
                smsVCodeRecordDay.setMobile(mobile);
                smsVCodeRecordDay.setIp(clientIp);
                smsVCodeRecordDay.setVCodeType(vCodeType);
                List<SmsVCodeRecord> vCodeRecordDay = smsVCodeRecordMapper.getRecordByMobileOrIp(smsVCodeRecordDay,
                        DateUtil.getTimesZeroClock(currentDate),
                        DateUtil.getTimesTwentyFourClock(currentDate));
                int dayLimit = PropertyUtil.getInt("sms.identity.verification.code.day.limit");
                if (vCodeRecordDay != null) {
                    // 获取验证码请求通过的数量
                    int allowTotal = 0;
                    for (SmsVCodeRecord item : vCodeRecordDay) {
                        if (item.getProcess() == EntityConsts.V_CODE_PROCESS_ALLOW) {
                            allowTotal++;
                        }
                    }
                    if (allowTotal >= dayLimit) {
                        int dayBlackLimit = PropertyUtil.getInt("sms.identity.verification.code.day.black.limit");
                        process = EntityConsts.V_CODE_PROCESS_LIMIT;
                        if (vCodeRecordDay.size() >= dayBlackLimit) {
                            needBlack = true;
                            process = EntityConsts.V_CODE_PROCESS_BLACK;
                        }
                    }
                }
            }
            // 验证码请求频率控制
            if (process == EntityConsts.V_CODE_PROCESS_ALLOW) {
                SmsVCodeRecord smsVCodeRecord = new SmsVCodeRecord();
                smsVCodeRecord.setMobile(mobile);
                smsVCodeRecord.setIp(clientIp);
                smsVCodeRecord.setVCodeType(vCodeType);
                int frequencyTime = PropertyUtil.getInt("sms.identity.verification.code.frequency.time");
                Date startTime = new Date(currentDate.getTime() - frequencyTime);
                List<SmsVCodeRecord> vCodeRecord = smsVCodeRecordMapper.getRecordByMobileOrIp(smsVCodeRecord, startTime, currentDate);
                if (vCodeRecord != null) {
                    // 除了重复请求的数量
                    int exceptRepeatTotal = 0;
                    for (SmsVCodeRecord item : vCodeRecord) {
                        if (item.getProcess() != EntityConsts.V_CODE_PROCESS_REPEAT) {
                            exceptRepeatTotal++;
                        }
                    }
                    if (exceptRepeatTotal > 0) {
                        process = EntityConsts.V_CODE_PROCESS_REPEAT;
                    }
                }
            }
        }
        // 保存请求记录
        SmsVCodeRecord insertSmsVCodeRecord = new SmsVCodeRecord();
        insertSmsVCodeRecord.setMobile(mobile);
        insertSmsVCodeRecord.setIp(clientIp);
        insertSmsVCodeRecord.setVCodeType(vCodeType);
        insertSmsVCodeRecord.setProcess(process);
        insertSmsVCodeRecord.setRequestTime(currentDate);
        smsVCodeRecordMapper.insert(insertSmsVCodeRecord);
        // 保存黑名单
        if (needBlack) {
            SmsVCodeBlackWhiteRecord insertSmsVCodeBlackWhiteRecord = new SmsVCodeBlackWhiteRecord();
            insertSmsVCodeBlackWhiteRecord.setMobile(mobile);
            insertSmsVCodeBlackWhiteRecord.setIp(clientIp);
            insertSmsVCodeBlackWhiteRecord.setVCodeType(vCodeType);
            insertSmsVCodeBlackWhiteRecord.setType(EntityConsts.V_CODE_BLACK_WHITE_TYPE_BLACK);
            insertSmsVCodeBlackWhiteRecord.setStartTime(currentDate);
            insertSmsVCodeBlackWhiteRecord.setEndTime(DateUtil.getTimesTwentyFourClock(currentDate));
            smsVCodeBlackWhiteRecordMapper.insert(insertSmsVCodeBlackWhiteRecord);
        }
        return process;
    }

    @Override
    public void cleanBeforeYesterdayRecord() {
        Date invalidDate = DateUtil.getTimesZeroClock(new Date());
        smsVCodeRecordMapper.cleanBeforeRecord(invalidDate);
        smsVCodeBlackWhiteRecordMapper.cleanBeforeRecord(invalidDate);
    }

    /**
     * 请求的验证码类型是否有限制
     * @param vCodeType
     * @return
     */
    private boolean isRestrictRequest(int vCodeType) {
        boolean isRestrictRequest = true;
        switch (vCodeType) {
            case EntityConsts.V_CODE_TYPE_ALL:
                break;
            case EntityConsts.V_CODE_TYPE_REGISTER:
                break;
            case EntityConsts.V_CODE_TYPE_LOGIN:
                isRestrictRequest = false;
                break;
            case EntityConsts.V_CODE_TYPE_CHANGE_PASSWORD:
                break;
            case EntityConsts.V_CODE_TYPE_ORDER:
                isRestrictRequest = false;
                break;
            case EntityConsts.V_CODE_TYPE_OTHER:
                break;
        }
        return isRestrictRequest;
    }
}
